package ess.hardware;

import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JLabel;

import ess.control.ElevatorManager;

public class FileOperationPanel extends javax.swing.JPanel implements ActionListener {
	
	
	
	JButton openBtn;
	JButton startBtn;
	JButton stopBtn;
	JLabel timeLabel;
	FileDialog fileDialog;
	Timer timer;
	Timestamp timestamp;
	Vector opList;
	Timer opTimer;
	
	public FileOperationPanel(){
		setLayout(new GridLayout(3,2));
		
		openBtn = new JButton("OPEN");
		add(openBtn);
		add(new JLabel(""));
		openBtn.addActionListener(this);
		
		startBtn = new JButton("START");
		add(startBtn);
		startBtn.setEnabled(false);
		startBtn.addActionListener(this);
		
		stopBtn = new JButton("STOP");
		add(stopBtn);
		stopBtn.setEnabled(false);
		stopBtn.addActionListener(this);
		
		timeLabel = new JLabel();
		
		timestamp = new Timestamp(0);
		SimpleDateFormat sdf = new SimpleDateFormat("mm:ss:SSS");
		timeLabel.setText(sdf.format(timestamp));
		
		
		add(timeLabel);
	}

	public void actionPerformed(ActionEvent event) {
		JButton btn = (JButton) event.getSource();
		
		if(btn.getText().equals("OPEN")){
			Frame f = new Frame();
			FileDialog fileDialog = new FileDialog(f, "Open", FileDialog.LOAD);
			fileDialog.setFile("*.scn");
			fileDialog.setVisible(true);
			
			String dirName = fileDialog.getDirectory();
			String fileName = fileDialog.getFile();
					
			System.out.println(dirName+fileName);
			
			try {
				if(readOperations(dirName, fileName)){
					startBtn.setEnabled(true);				
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(btn.getText().equals("START")){
			
			timer = null;
			timer = new Timer();
			
			timestamp = new Timestamp(0);

			TimerLabelTimerTask timerTask = new TimerLabelTimerTask(timeLabel, timestamp);
			timer.schedule(timerTask,10,10);
			
			
			opTimer = new Timer();
			timer.schedule(new OperationTimerTask(opList, opTimer), 0);
			startBtn.setEnabled(false);
			stopBtn.setEnabled(true);
			
			
		}
		if(btn.getText().equals("STOP")){
			stopBtn.setEnabled(false);
			timer.cancel();
			opTimer.cancel();
			
		}
	}

	private boolean readOperations(String dirName, String fileName) throws IOException {
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(dirName+fileName));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		}
		
		
		if(opList != null){
			opList.clear();
			opList = null;
		}
		
		opList = new Vector();
		
		String line = null;
		try {
			
			while((line = br.readLine()) != null){
				line = line.trim();
				if(line.startsWith("//") || line.length() == 0) continue;
				

				int type = 0;
				long delay = 0;
				int value1 = 0;
				int value2 = 0;
				String token = "";
				
				StringTokenizer st = new StringTokenizer(line,",");
				if(st.hasMoreTokens()){
					//type
					token = st.nextToken();
					if(token.equalsIgnoreCase("FloorOperation")){
						type = Operation.TYPE_FLOOR_OPERATION;
						
						token = st.nextToken();
						value1 = new Integer(token).intValue(); //location
						
						token = st.nextToken();
						if(token.equalsIgnoreCase("UP")){
							value2 = Operation.VALUE_UP;
						} else {
							value2 = Operation.VALUE_DOWN;
						}
						
					} else if(token.equalsIgnoreCase("ElevatorOperation")){
						type = Operation.TYPE_ELEVATOR_OPERATION;
						
						token = st.nextToken();
						value1 = new Integer(token).intValue(); //elevator #
						
						token = st.nextToken();
						value2 = new Integer(token).intValue(); //target floor #
					
					} else if(token.equalsIgnoreCase("DoorOperation")){
						type = Operation.TYPE_DOOR_OPERATION;
						
						token = st.nextToken();
						value1 = new Integer(token).intValue(); //elevator #
						
						token = st.nextToken();
						if(token.equalsIgnoreCase("OPEN")){
							value2 = Operation.VALUE_OPEN;
						} else {
							value2 = Operation.VALUE_CLOSE;
						}
					} else if(token.equalsIgnoreCase("ObstacleOperation")){
						type = Operation.TYPE_OBSTACLE_OPERATIION;
						
						token = st.nextToken();
						value1 = new Integer(token).intValue(); //elevator #
						
						token = st.nextToken();
						if(token.equalsIgnoreCase("ON")){
							value2 = Operation.VALUE_ON;
						} else {
							value2 = Operation.VALUE_OFF;
						}
					}
					else{
						System.out.println(line);
						Thread.dumpStack();
						return false;
					}
					
					//delay
					token = st.nextToken();
					delay = new Integer(token).longValue();
					
					System.out.println("operation added");
					opList.add(new Operation(type,delay,value1,value2));
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		
		if(br != null) br.close();
		
		if(opList != null && opList.isEmpty() == false){ 
			System.out.println("readOperations");
			System.out.println(opList.size());
			return true;
		}
		
		return false;
	}
	
	class TimerLabelTimerTask extends TimerTask{
		JLabel timerLabel;
		Timestamp timestamp;
		public TimerLabelTimerTask(JLabel label, Timestamp time){
			timerLabel = label;
			this.timestamp = time;
		}

		public void run() {
			timestamp.setTime(timestamp.getTime()+10);
			SimpleDateFormat sdf = new SimpleDateFormat("mm:ss:SS");
			
			timerLabel.setText(sdf.format(timestamp));
			 
			
			timerLabel.repaint();
		}
		
	}
	
	class OperationTimerTask extends TimerTask{
		Vector opList;
		Timer timer;
		Operation op = null;
		public OperationTimerTask(Vector opList, Timer timer){
			this.opList = opList;
			this.timer = timer;
		}
		
		public void run() {
			
			if(opList == null || opList.isEmpty()) return;
			
			op = (Operation) opList.remove(0);
			if( op.type == Operation.TYPE_FLOOR_OPERATION ){
				int operationValue = op.value2 == Operation.VALUE_UP ? FloorOperationEvent.VALUE_UP : FloorOperationEvent.VALUE_DOWN;
				ElevatorManager.getInstance().operationOccured(new FloorOperationEvent(op.value1, FloorOperationEvent.TYPE_CALL, operationValue));
				System.out.println("send FloorOp");
			} else if( op.type == Operation.TYPE_ELEVATOR_OPERATION){
				int type = ElevatorOperationEvent.TYPE_SELECT_FLOOR;
				ElevatorManager.getInstance().getElevatorProxy(op.value1).operationOccured(new ElevatorOperationEvent(null, type, op.value2));
			} else if( op.type == Operation.TYPE_DOOR_OPERATION ){
				int type = ElevatorOperationEvent.TYPE_OPEN_CLOSE;
				int value = op.value2 == Operation.VALUE_OPEN ? ElevatorOperationEvent.VALUE_OPEN : ElevatorOperationEvent.VALUE_CLOSE;
				ElevatorManager.getInstance().getElevatorProxy(op.value1).operationOccured(new ElevatorOperationEvent(null, type, value));
			} else if( op.type == Operation.TYPE_OBSTACLE_OPERATIION ){
				// TODO:
			}
			System.out.println("OperationTimerTask");
			System.out.println(opList.size());
			if(opList.isEmpty() == false){
				System.out.println(op.delay);
				timer.schedule(new OperationTimerTask(opList, timer), op.delay);
			}
			
		}
	}
	
	class Operation{
		static final int TYPE_FLOOR_OPERATION = 1;
		static final int TYPE_ELEVATOR_OPERATION = 2;
		static final int TYPE_DOOR_OPERATION = 3;
		static final int TYPE_OBSTACLE_OPERATIION = 4;
		
		static final int VALUE_UP = 1;
		static final int VALUE_DOWN = 2;
		static final int VALUE_OPEN = 3;
		static final int VALUE_CLOSE = 4;
		static final int VALUE_ON = 5;
		static final int VALUE_OFF = 5;
		
		//delay in millisec,FloorOperation,at,up/down
		//delay,ElevatorOperation, Elevator#, targetFloor#
		//delay,DoorOperation,Elevator#, open/close
		//delay,OpstacleOperation,Elevator#, on/off
		//0,FloorRequest,5,up
		//100,ElevatorCall,1,5
		//50,DoorOperation,1,close
		int type;
		long delay;
		int value1;
		int value2;
		
		public Operation(int type, long delay, int value1, int value2){
			this.type = type;
			this.delay = delay;
			this.value1 = value1;
			this.value2 = value2;
		}
	}
	
	
}
